#pragma once

#include "Query.h"
#include "QueryModifies.h"
#include "QueryFollows.h"
#include "QueryUses.h"
#include "QueryParent.h"
#include "QueryPattern.h"
#include "QueryFollowsStar.h"
#include "QueryParentStar.h"
#include "CompleteQuery.h"

/* ------------------------------------------------------------------------------------------
* A singleton class that takes in a QueryType:
*	QueryType: Modifies, Uses, Follows or Parent
* and a list of Synonym:
*	Synonym: Assignment, Procedure, Procedure Literal, Statement, Variable Literal or While
* and returns a Query object.
*
* Since patterns take in 3 variables instead of 2 (unlike modifies etc), a constructor is
* overloaded to handle pattern queries.
* 
* Example: Creating a Modifies query (Modifies(1,"a"))
* QueryCreator *queryCreator = QueryCreator::getQueryCreator();
* 
* QueryType queryType = MODIFIES;
* VAR_TYPE type1 = ASSIGN;
* VAR_TYPE type2 = STATEMENT;
* Synonym *assignType = new Synonym(type1, "a");
* Synonym *statementType = new Synonym(type2, "1");
*
* Query *mod = queryCreator->createQuery(queryType, statementNumber, varLiteral);
*
* End Example
*
* The Query object can then be passed over to QueryEvaluator for processing.
* ------------------------------------------------------------------------------------------- */


class QueryCreator {
private:
	static QueryCreator *queryCreator; /**< The singleton instance of the query creator */
	CompleteQuery *currentQuery; /**< The complete format of the query */
	
	/** Constructor
	 * Constructs a query creator
	 */
	QueryCreator();

public:
	/** 
	 * Gets the singleton instance of the query creator
	 * @return the query creator
	 */
	static QueryCreator *getQueryCreator();

	/** 
	 * Creates a new query
	 */
	void createNewQuery();
	
	/** 
	 * Adds a synonym to the complete query
	 * @param syn the synonym to be added
	 */
	void addSynonym(Synonym *syn);

	/** 
	 * Adds a result to the complete query
	 * @param result the result to be added
	 */
	void addResult(Result *result);

	/** 
	 * Adds a query of a query type with 2 arguments to the complete query
	 * @param queryType the type of query
	 * @param arg1 the first argument of the query
	 * @param arg2 the second argument of the query
	 */
	void addQuery(QueryType queryType, Synonym *arg1, Synonym *arg2);
	
	/** 
	 * Adds a query of a query type with 3 arguments to the complete query
	 * @param queryType the type of query
	 * @param arg1 the first argument of the query
	 * @param arg2 the second argument of the query
	 * @param arg3 the third argument of the query
	 */
	void addQuery(QueryType queryType, Synonym *arg1, Synonym *arg2, Synonym *arg3);
	
	/** 
	 * Gets the entire complete query
	 * @return the complete query
	 */
	CompleteQuery *getCompleteQuery();

	/** Destructor
	 * Cleans up the query creator
	 */
	~QueryCreator();
};